home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 10 / FM Towns Free Software Collection 10.iso / ms_dos / tool / mercury / install.c < prev    next >
Text File  |  1995-02-05  |  17KB  |  770 lines

  1. /*
  2.  
  3. MercuryInstaller for MS-DOS
  4. インストール&QQQファイル処理ルーチン
  5.  
  6. */
  7.  
  8. #include<ctype.h>
  9. #include<direct.h>
  10. #include<dos.h>
  11. #include<farstr.h>
  12. #include<fcntl.h>
  13. #include<io.h>
  14. #include<jstring.h>
  15. #include<setjmp.h>
  16. #include<stdio.h>
  17. #include<stdlib.h>
  18. #include<string.h>
  19. #include<sys/stat.h>
  20.  
  21. #include"mercury.h"
  22.  
  23. /*****************************************************************************/
  24. /*                              グローバル変数                               */
  25. /*****************************************************************************/
  26. static    char    Sourcedir[128] = "";    /* コピー元のディレクトリ  */
  27. static    int    Qqqlevel = 0;        /* QQQファイルの再帰レベル */
  28. /*****************************************************************************/
  29. /*                               下請け処理                                  */
  30. /*****************************************************************************/
  31. /*-----------------------------コピー元パスの作成----------------------------*/
  32. /* 指定されたパスが相対パスによるものであれば、それにドライブ名・パス名をつけ*/
  33. /* 加える                                                                    */
  34. /*---------------------------------------------------------------------------*/
  35. static    void    mksourcepath(char *d,char *s)
  36. {
  37.     if    (s[1]==':')            /* ドライブ名から指定       */
  38.         strcpy(d,s);
  39.     else if    (s[0]=='\\')            /* 標準ドライブのルートから指定  */
  40.         sprintf(d,"%c:%s",Drive,s);
  41.     else                    /* 標準ディレクトリから指定 */
  42.         sprintf(d,"%c:%s\\%s",Drive,Sourcedir,s);
  43.  
  44.     if    (Sourcedir[0]=='\0')
  45.     {
  46.         char    *p;
  47.  
  48.         if    (s[1]==':')
  49.             strcpy(Sourcedir,s+2);
  50.         else if    (s[0]=='\\')
  51.             strcpy(Sourcedir,s);
  52.  
  53.         p = jstrrchr(Sourcedir,'\\');
  54.         if    (p!=NULL)
  55.             *p = '\0';
  56.     }
  57. }
  58. /*---------------ディレクトリが存在するかどうかチェック----------------------*/
  59. static    int    is_directory_exist(char *path)
  60. {
  61.     char    buf[128];
  62.  
  63.     if    (getcwd(buf,sizeof(buf))==NULL)
  64.         return 0;
  65.  
  66.     if    (chdir(path)!=0)
  67.         return 0;
  68.  
  69.     chdir(buf);
  70.     return 1;
  71. }
  72. /*------------------------パス名の直後の位置を探す---------------------------*/
  73. static    char    *afterpath(char *s)
  74. {
  75.     char    *p = jstrrchr(s,'\\');
  76.  
  77.     if    (p!=NULL)
  78.         return p+1;
  79.     else if    (s[1]==':')
  80.         return s+2;
  81.     else
  82.         return s;
  83. }
  84. /*----------------------パス名の最後に'\\'をつけ加える-----------------------*/
  85. /* 関数の値としては'\\'をつけ加えた後の位置を返す。                          */
  86. /*---------------------------------------------------------------------------*/
  87. static    char    *addbackslash(char *s)
  88. {
  89.     char    *p = strchr(s,'\0');
  90.  
  91.     if    (p!=s && p[-1]!='\\' && p[-1]!=':')
  92.     {
  93.         p[0] = '\\';
  94.         p[1] = '\0';
  95.         return p+1;
  96.     }
  97.     else
  98.         return p;
  99. }
  100. /*****************************************************************************/
  101. /*                               QQQファイル                                 */
  102. /*****************************************************************************/
  103. /*-----------------各コマンド処理ルーチンのプロトタイプ宣言------------------*/
  104. /* 本当は私、static関数のプロトタイプ宣言は嫌いなんですが...(^_^;)こうしない */
  105. /* と、ifコマンドの処理で間接再帰を使うのでうまく書けないのです(;_;)。       */
  106. /*---------------------------------------------------------------------------*/
  107. static    int    cmd_dummy(char *);
  108. static    int    cmd_chdir(char *);
  109. static    int    cmd_copy(char *);
  110. static    int    cmd_exit(char *);
  111. static    int    cmd_if(char *);
  112. static    int    cmd_inst(char *);
  113. static    int    cmd_look(char *);
  114. static    int    cmd_mkdir(char *);
  115. static    int    cmd_pause(char *);
  116. static    int    cmd_rename(char *);
  117. static    int    cmd_xcopy(char *);
  118. /*-------------------------------型と変数------------------------------------*/
  119. static    struct    COMMANDS
  120. {
  121.     char    *str;
  122.     int    (*func)(char *);
  123. } Commands[] = 
  124. {
  125.     {"chdir" ,cmd_chdir },
  126.     {"copy"  ,cmd_copy  },
  127.     {"else"  ,cmd_dummy },
  128.     {"endif" ,cmd_dummy },
  129.     {"exit"  ,cmd_exit  },
  130.     {"if"    ,cmd_if    },
  131.     {"inst"  ,cmd_inst  },
  132.     {"look"  ,cmd_look  },
  133.     {"mkdir" ,cmd_mkdir },
  134.     {"pause" ,cmd_pause },
  135.     {"play"  ,cmd_dummy },
  136.     {"rename",cmd_rename},
  137.     {"xcopy" ,cmd_xcopy },
  138. };
  139.  
  140. typedef    enum
  141. {
  142.     CMD_CHDIR,CMD_COPY,CMD_ELSE,CMD_ENDIF,CMD_EXIT,CMD_IF,CMD_INST,
  143.     CMD_LOOK,CMD_MKDIR,CMD_PAUSE,CMD_PLAY,CMD_RENAME,CMD_XCOPY,
  144.     CMD_EOF,
  145. } COMMANDID;
  146.  
  147. jmp_buf    Jmp_buf;
  148. /*----------------------QQQファイルのアクセスルーチン------------------------*/
  149. /* qqq_fgetsは、*argに内部のstaticバッファへのポインタを返す。従って、次に呼 */
  150. /* ばれるまでその内容は有効。                                                */
  151. /*---------------------------------------------------------------------------*/
  152. static    FILE    *Qqqfile[FOPEN_MAX+1];    /* 1..FOPEN_MAX */
  153.  
  154. static    int    qqq_fopen(char *filename)
  155. {
  156.     char    buf[128];
  157.     FILE    *fp;
  158.  
  159.     mksourcepath(buf,filename);
  160.  
  161.     fp = fopen(buf,"r");
  162.     if    (fp==NULL)
  163.     {
  164.         putmessage("%sがオープンできません",buf);
  165.         return 0;
  166.     }
  167.  
  168.     Qqqfile[++Qqqlevel] = fp;
  169.     return 1;
  170. }
  171.  
  172. static    void    qqq_fclose(void)
  173. {
  174.     fclose(Qqqfile[Qqqlevel--]);
  175. }
  176.  
  177. static    COMMANDID    qqq_fgets(char **arg)
  178. {
  179.     static    char    buf[512];
  180.     char        *p,*q;
  181.     int        i;
  182.  
  183. rep:
  184.     if    (Qqqlevel==0)
  185.         return CMD_EOF;
  186.  
  187.     if    (fgets(buf,sizeof(buf),Qqqfile[Qqqlevel])==NULL)
  188.     {
  189.         qqq_fclose();
  190.         goto rep;
  191.     }
  192.  
  193.     if    ((p=strchr(buf,'\n'))!=NULL)
  194.         *p = '\0';
  195.  
  196.     p = buf;
  197.     while    (isspace(*p))
  198.         p++;
  199.  
  200.     if    (*p=='#' || *p=='\0')
  201.         goto rep;
  202.  
  203.     q = p;
  204.  
  205.     while    (isalpha(*p))
  206.         p++;
  207.     *p = '\0';
  208.  
  209.     do
  210.         p++;
  211.     while    (isspace(*p));
  212.     *arg = p;
  213.  
  214.     for    (i=0 ; i<MEMBERSOF(Commands) ; i++)
  215.     {
  216.         if    (stricmp(q,Commands[i].str)==0)
  217.             return (COMMANDID)i;
  218.     }
  219.  
  220.     putmessage("QQQファイルに不正な命令があります:%s",q);
  221.     longjmp(Jmp_buf,-1);
  222. }
  223.  
  224. static    void    qqq_release(void)
  225. {
  226.     while    (Qqqlevel)
  227.         qqq_fclose();
  228. }
  229. /*-----------------QQQファイル解釈ルーチンのメインルーチン-------------------*/
  230. static    int    qqqinterpreter(char *filename)
  231. {
  232.     char        *p;
  233.     int        a;
  234.     COMMANDID    id;
  235.  
  236.     if    (!qqq_fopen(filename))
  237.         return 0;
  238.  
  239.     a = setjmp(Jmp_buf);
  240.     if    (a!=0)
  241.     {
  242.         qqq_release();
  243.         if    (a<0)    return 0;
  244.         else        return 1;
  245.     }
  246.  
  247.     while    ((id=qqq_fgets(&p))!=CMD_EOF)
  248.     {
  249.         if    (!Commands[id].func(p))
  250.         {
  251.             qqq_release();
  252.             return 0;
  253.         }
  254.     }
  255.  
  256.     qqq_release();
  257.  
  258.     return 1;
  259. }
  260. /*****************************************************************************/
  261. /*                        QQQファイルの各コマンドの処理                      */
  262. /*****************************************************************************/
  263. /*-----------------------------ダミーコマンド--------------------------------*/
  264. static    int    cmd_dummy(char *s)
  265. {
  266.     return 1;
  267. }
  268. /*------------------------------chdirコマンド--------------------------------*/
  269. static    int    cmd_chdir(char *s)
  270. {
  271.     if    (chdir(s)==0)
  272.         return 1;
  273.  
  274.     putmessage("ディレクトリ%sがありません");
  275.     return 0;
  276. }
  277. /*-------------------------------copyコマンド--------------------------------*/
  278. static    int    cmd_copy(char *s)
  279. {
  280.     char    *p = s;
  281.  
  282.     static    int    copy(int f,char *s,char *d);
  283.  
  284.     while    (!isspace(*p))
  285.         p++;
  286.  
  287.     if    (*p!='\0')
  288.     {
  289.         *p++ = '\0';
  290.         while    (isspace(*p))
  291.             p++;
  292.     }
  293.  
  294.     return copy(0,s,p);
  295. }
  296. /*------------------------------exitコマンド---------------------------------*/
  297. static    int    cmd_exit(char *s)
  298. {
  299.     longjmp(Jmp_buf,1);
  300. }
  301. /*-------------------------------ifコマンド----------------------------------*/
  302. static    int    cmd_if(char *mes)
  303. {
  304.     COMMANDID    id;
  305.     char        *p;
  306.     int        c;
  307.  
  308.     c = window_select(mes,"Y:はい","N:いいえ",NULL);
  309.  
  310.     if    (c=='Y' || c=='y')
  311.     {
  312.         while    ((id=qqq_fgets(&p))!=CMD_ELSE &&
  313.                 id!=CMD_ENDIF && id!=CMD_EOF)
  314.         {
  315.             if    (!Commands[id].func(p))
  316.                 return 0;
  317.         }
  318.  
  319.         if    (id==CMD_ELSE)
  320.         {
  321.             while    ((id=qqq_fgets(&p))!=CMD_ENDIF && id!=CMD_EOF)
  322.                 ;
  323.         }
  324.     }
  325.     else
  326.     {
  327.         while    ((id=qqq_fgets(&p))!=CMD_ELSE &&
  328.                 id!=CMD_ENDIF && id!=CMD_EOF)
  329.             ;
  330.  
  331.         if    (id==CMD_ELSE)
  332.         {
  333.             while    ((id=qqq_fgets(&p))!=CMD_ENDIF && id!=CMD_EOF)
  334.             {
  335.                 if    (!Commands[id].func(p))
  336.                     return 0;
  337.             }
  338.         }
  339.     }
  340.  
  341.     return 1;
  342. }
  343. /*-------------------------------instコマンド--------------------------------*/
  344. static    int    cmd_inst(char *s)
  345. {
  346.     return qqq_fopen(s);
  347. }
  348. /*-------------------------------lookコマンド--------------------------------*/
  349. /* Helperとの互換性のため一応ダミーを用意しておく                            */
  350. /*---------------------------------------------------------------------------*/
  351. static    int    cmd_look(char *s)
  352. {
  353.     openwindow(2,64);
  354.     window_putstr(0,"LOOK:\n%s",s);
  355.     ds_getch();
  356.     closewindow();
  357.     return 1;
  358. }
  359. /*------------------------------mkdirコマンド--------------------------------*/
  360. static    int    cmd_mkdir(char *s)
  361. {
  362.     if    (mkdir(s)==0)
  363.         return 1;
  364.  
  365.     putmessage("ディレクトリ%sが作れません");
  366.     return 0;
  367. }
  368. /*-------------------------------pauseコマンド-------------------------------*/
  369. static    int    cmd_pause(char *s)
  370. {
  371.     openwindow(1,strlen(s)+1);
  372.     window_putstr(0,"%s",s);
  373.     ds_getch();
  374.     closewindow();
  375.     return 1;
  376. }
  377. /*------------------------------renameコマンド-------------------------------*/
  378. static    int    cmd_rename(char *s)
  379. {
  380.     char    *p = s;
  381.  
  382.     while    (!isspace(*p))
  383.         p++;
  384.  
  385.     if    (*p=='\0')
  386.     {
  387.         putmessage("RENAMEコマンドの書式が不正です");
  388.         return 0;
  389.     }
  390.  
  391.     *p = '\0';
  392.     while    (isspace(*p))
  393.         p++;
  394.  
  395.     if    (rename(s,p)==0)
  396.         return 1;
  397.  
  398.     putmessage("RENAMEできませんでした");
  399.     return 0;
  400. }
  401. /*------------------------------xcopyコマンド--------------------------------*/
  402. static    int    cmd_xcopy(char *s)
  403. {
  404.     char    *p = s;
  405.  
  406.     static    int    copy(int f,char *s,char *d);
  407.  
  408.     while    (!isspace(*p))
  409.         p++;
  410.  
  411.     if    (*p!='\0')
  412.     {
  413.         *p++ = '\0';
  414.         while    (isspace(*p))
  415.             p++;
  416.     }
  417.  
  418.     return copy(1,s,p);
  419. }
  420. /*****************************************************************************/
  421. /*                             ファイルのコピー                              */
  422. /*****************************************************************************/
  423. /*------------------------単一ファイルのコピー-------------------------------*/
  424. /*  次の要件を満たすとき、srcをQQQファイルとみなしてqqqinterpreter()を呼び出 */
  425. /* す。                                                                      */
  426. /*    ○srcが示すのがQQQファイルである                                       */
  427. /*    ○このcopy_onefile()がQQQファイルの(X)COPY命令から呼ばれたものでない   */
  428. /*      すなわち、QQQlevel==0                                                */
  429. /*---------------------------------------------------------------------------*/
  430. /* なぜか高水準入出力を使うと極端にパフォーマンスが落ちるので、あえて低水準  */
  431. /* 入出力を使用している                                                      */
  432. /*---------------------------------------------------------------------------*/
  433. static    int    copy_onefile(char *src,char *dst)
  434. {
  435.     int    fdi=-1,fdo=-1;
  436.     long    size,size2;
  437.     int    n;
  438.  
  439.     char    buf[4096];
  440.  
  441.     if    (Qqqlevel==0)
  442.     {
  443.         char    *p = strchr(src,'\0');
  444.  
  445.         if    (p>src+4 && stricmp(p-4,".qqq")==0)
  446.             return qqqinterpreter(src);
  447.     }
  448.  
  449.     openwindow(4,64);
  450.     diet_setmode(0);
  451.  
  452.     fdi=open(src,O_RDONLY);
  453.     if    (fdi==-1)
  454.     {
  455.         window_putstr(0,"%sがオープンできません",src);
  456.         ds_getch();
  457.         goto error;
  458.     }
  459.  
  460.     fdo=open(dst,O_WRONLY|O_TRUNC|O_CREAT,S_IREAD|S_IWRITE);
  461.     if    (fdo==-1)
  462.     {
  463.         window_putstr(0,"%sがオープンできません",dst);
  464.         ds_getch();
  465.         goto error;
  466.     }
  467.  
  468.     size  = filelength(fdi);
  469.     size2 = 0;
  470.     window_putstr(0,"%s\n",dst);
  471.     window_putstr(3,"[ESC]/[F10]で中止します");
  472.  
  473.     {
  474.         unsigned    date,time;
  475.  
  476.         _dos_getftime(fdi,&date,&time);
  477.         _dos_setftime(fdo,date,time);
  478.     }
  479.  
  480.     while    ((n=read(fdi,buf,sizeof(buf)))>0) /* エラー処理は少々手抜き */
  481.     {
  482.         if    (write(fdo,buf,n)==-1)
  483.             goto error;
  484.  
  485.         size2 += n;
  486.         window_putstr(2,"%ld/%ld",size2,size);
  487.  
  488.         if    (ds_kbhit())
  489.         {
  490.             int    c = ds_getch();
  491.  
  492.             if    (c==FKEY_ESC || c==FKEY_F10)
  493.             {
  494.                 closewindow();
  495.                 openwindow(1,14);
  496.                 window_putstr(0,"中止しました.");
  497.                 goto error;
  498.             }
  499.         }
  500.     }
  501.  
  502.     close(fdi);
  503.     close(fdo);
  504.     closewindow();
  505.     diet_setmode(1);
  506.     return 1;
  507.  
  508. error:
  509.     if    (fdi!=NULL)    close(fdi);
  510.     if    (fdo!=NULL)    close(fdo);
  511.  
  512.     closewindow();
  513.     diet_setmode(1);
  514.     return 0;
  515. }
  516. /*--------------------ファイルを検索して線形リストに格納---------------------*/
  517. struct    DIRCHAIN
  518. {
  519.     char        name[13];
  520.     char        attr;
  521.     unsigned    time;
  522.     unsigned    date;
  523.     unsigned long    size;
  524.     struct DIRCHAIN    *next;
  525. };
  526.  
  527. struct DIRCHAIN    *ds_opndir(char *path, char attr)
  528. {
  529.     char        *chp;
  530.     struct find_t    fib;
  531.     struct DIRCHAIN    *dirtop;
  532.     struct DIRCHAIN    *dir;
  533.     static char    buf[128];
  534.  
  535.     strncpy(buf, path, sizeof(buf)-1);
  536.     chp = strchr(buf,'\0') -1;
  537.  
  538.     if (*chp==':' || *chp=='\\')
  539.         strncat(buf, "*.*", sizeof(buf) - 1);
  540.  
  541.     if    (_dos_findfirst(buf, (unsigned)attr, &fib))
  542.         return NULL;
  543.     if ((dir = malloc(sizeof(struct DIRCHAIN))) == NULL)
  544.         return NULL;
  545.     dirtop = dir;
  546.     strcpy(dir->name, fib.name);
  547.     dir->attr = fib.attrib;
  548.     dir->time = fib.wr_time;
  549.     dir->date = fib.wr_date;
  550.     dir->size = fib.size;
  551.     dir->next = NULL;
  552.     while (_dos_findnext(&fib) == 0)
  553.     {
  554.         if ((dir->next = malloc(sizeof(struct DIRCHAIN))) == NULL)
  555.             return NULL;
  556.         dir = dir->next;
  557.         strcpy(dir->name, fib.name);
  558.         dir->attr = fib.attrib;
  559.         dir->time = fib.wr_time;
  560.         dir->date = fib.wr_date;
  561.         dir->size = fib.size;
  562.         dir->next = NULL;
  563.     }
  564.     return dirtop;
  565. }
  566. /*-----------------単一ファイル→単一ファイルのコピーか?---------------------*/
  567. static    int    is_single_to_single(char *src,char *dst)
  568. {
  569.     char    *p;
  570.  
  571.     if    (jstrchr(src,'*')!=NULL || jstrchr(src,'?')!=NULL)
  572.         return 0;
  573.  
  574.     p = strchr(dst,'\0');
  575.     if    (p==dst || p[-1]=='\\' || p[-1]==':')
  576.         return 0;
  577.  
  578.     if    (is_directory_exist(dst))
  579.         return 0;
  580.  
  581.     if    (access(src,4)==0)
  582.         return 1;
  583.     else
  584.         return 0;
  585. }
  586. /*----------------指定されたパスの親ディレクトリがなければ作る---------------*/
  587. static    int    mkparentdir(char *path)
  588. {
  589.     char    *p;
  590.     int    n = 0;
  591.  
  592.     while    ((p=jstrrchr(path,'\\'))!=NULL)
  593.     {
  594.         *p = '\0';
  595.         n++;
  596.         if    (chdir(path)==0)
  597.             break;
  598.     }
  599.  
  600.     for    ( ; n ; *strchr(path,'\0')='\\',n--)
  601.     {
  602.         char    buf[128];
  603.         int    c;
  604.  
  605.         if    (chdir(path)==0)
  606.             continue;
  607.         if    (path[0]=='\0' || (path[1]==':' && path[2]=='\0'))
  608.             continue;
  609.  
  610.         strcpy(buf,path);
  611.         strcat(buf,"\nディレクトリが存在しません 作りますか?");
  612.  
  613.         c = window_select(buf,"Y:はい","N:いいえ",NULL);
  614.         if    (c=='N' || c=='n')
  615.             goto error;
  616.  
  617.         if    (mkdir(path)!=0)
  618.         {
  619.             putmessage("ディレクトリ%sが作れません",path);
  620.             goto error;
  621.         }
  622.     }
  623.     return 1;
  624.  
  625. error:
  626.     while    (n--)
  627.         *strchr(path,'\0') = '\\';
  628.  
  629.     return 0;
  630. }
  631. /*-------------------------COPY/XCOPYの下請け再帰関数------------------------*/
  632. /* srcとdstの内容は破壊されるので注意                                        */
  633. /*---------------------------------------------------------------------------*/
  634. recursive static int    xcopy_sub(int isxcopy,char *src,char *dst)
  635. {
  636.     char        *s = afterpath(src);
  637.     char        *d = afterpath(dst);
  638.     struct DIRCHAIN    *dir = ds_opndir(src,_A_NORMAL|_A_SUBDIR);
  639.  
  640.     while    (dir!=NULL)
  641.     {
  642.         struct DIRCHAIN    *temp;
  643.  
  644.         if    (dir->name[0]=='.')
  645.             goto next;
  646.  
  647.         strcpy(s,dir->name);
  648.         strcpy(d,dir->name);
  649.  
  650.         if    (dir->attr & _A_SUBDIR)
  651.         {
  652.             if    (!isxcopy)
  653.             {
  654.                 char    buf[128];
  655.                 int    c;
  656.  
  657.                 sprintf(buf,"%sディレクトリもコピーしますか?",
  658.                                 dir->name);
  659.  
  660.                 c=window_select(buf,"Y:はい","N:いいえ",NULL);
  661.                 if    (c=='N' || c=='n')
  662.                     goto next;
  663.             }
  664.  
  665.             if    (!is_directory_exist(dst) && mkdir(dst))
  666.             {
  667.                 putmessage("ディレクトリ%sが作れません",dst);
  668.                 goto error;
  669.             }
  670.  
  671.             strcat(s,"\\*.*");
  672.             strcat(d,"\\");
  673.             if    (!xcopy_sub(isxcopy,src,dst))
  674.                 goto error;
  675.         }
  676.         else
  677.         {
  678.             if    (!copy_onefile(src,dst))
  679.                 goto error;
  680.         }
  681.     next:
  682.         temp = dir;
  683.         free(dir);
  684.         dir = temp->next;
  685.     }
  686.  
  687.     return 1;
  688.  
  689. error:
  690.     while    (dir!=NULL)
  691.     {
  692.         struct DIRCHAIN    *temp = dir;
  693.  
  694.         free(dir);
  695.         dir = temp->next;
  696.     }
  697.  
  698.     return 0;
  699. }
  700. /*---------------------------コピーのメインルーチン--------------------------*/
  701. static    int    copy(int isxcopy,char *src,char *dst)
  702. {
  703.     char    src2[128];
  704.     char    dst2[128];
  705.  
  706.     mksourcepath(src2,src);
  707.     strcpy(dst2,dst);
  708.  
  709.     if    (is_single_to_single(src2,dst2))
  710.     {
  711.         if    (!mkparentdir(dst2))
  712.             return 0;
  713.         else
  714.             return copy_onefile(src2,dst2);
  715.     }
  716.  
  717.     addbackslash(dst2);
  718.  
  719.     if    (!mkparentdir(dst2))
  720.         return 0;
  721.  
  722.     return xcopy_sub(isxcopy,src2,dst2);
  723. }
  724. /*****************************************************************************/
  725. /*                         インストーラのメインルーチン                      */
  726. /*****************************************************************************/
  727. extern    void    installer(struct DATA far *data)
  728. {
  729.     static    char        target[128] = "";
  730.     char            buf[128];
  731.     struct    COPYDATA_T far    *p;
  732.     char            *s;
  733.  
  734.     strcpy(buf,target);
  735.     if    (!window_strinput("インストール先のディレクトリを指定してください",buf,64))
  736.         return;
  737.  
  738.     if    (data->dir!=NULL)
  739.         far_strcpy(Sourcedir,data->dir);
  740.     else
  741.         Sourcedir[0] = '\0';    /* qqqinterpreter()で設定する? */
  742.  
  743.     strcpy(target,buf);
  744.     s = addbackslash(buf) - 1;
  745.     if    (!mkparentdir(buf))
  746.         return;
  747.  
  748.     if    (s!=buf && s[-1]!=':')
  749.         *s = '\0';
  750.  
  751.     chdir(buf);
  752.     if    (buf[1]==':')
  753.         bdos(0x0e,toupper(buf[0])-'A',0);
  754.  
  755.     if    (data->copy==NULL)
  756.     {
  757.         copy(0,"*.*","");
  758.         return;
  759.     }
  760.  
  761.     for    (p=data->copy ; p!=NULL ; p=p->next)
  762.     {
  763.         far_strcpy(buf,p->string);
  764.  
  765.         if    (!copy(p->isxcopy,buf,""))
  766.             return;
  767.     }
  768. }
  769. /*-----------------------------End of install.c------------------------------*/
  770.